/* 文档说明： */
/*  主要功能：包装服务端     */
#pragma once

#include "TcpSocket.hpp"
#include "Log.hpp"
#include "Servecal.hpp"
#include <signal.h>
#include <functional>

using func_t = std::function<std::string(std::string &)>;

extern Log lg;

class TcpServe // 服务端服务器
{
public:
    TcpServe(uint16_t port, func_t func)
        : _port(port), _callback(func)
    {
    }
    ~TcpServe()
    {
    }

public:
    bool Init() // 服务器的初始化函数
    {
        // 底层已经封装了日志功能
        _listensock.Socket();    // 创建套接字
        _listensock.Bind(_port); // bind
        _listensock.Listen();    // 监听
        lg(Info, "Serve Init Success...");

        return true;
    }
    void Start() // 服务器的启动函数
    {
        signal(SIGCHLD, SIG_IGN); // 父进程不再等待子进程退出，资源自动回收
        signal(SIGPIPE, SIG_IGN);
        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = _listensock.Accept(&clientip, &clientport);
            if (sockfd < 0)
                continue; // 继续进行新的连接
            lg(Info, "Get a new link... ip: %s, port: %d, fd: %d", clientip.c_str(), clientport, sockfd);

            // 对外提供服务：我们这里采用多进程的方式 —> 简单
            if (fork() == 0)
            {
                // 子进程
                _listensock.Close();
                std::string buffer_stream; // 十分重要！！
                while (true)
                {
                    // 通信逻辑...
                    char buffer[128] = {0};
                    int ret_rd = read(sockfd, buffer, sizeof(buffer));
                    if (ret_rd > 0)
                    {
                        // 处理数据
                        buffer[ret_rd] = 0; //处理成字符串
                        buffer_stream += buffer; // 使用+=的原因是不一定读到的是完成的buffer
                        while (true) //为了处理buffer_stream中含有多个完整的报文结构
                        {
                            std::string ret = _callback(buffer_stream);
                            if(ret.empty()) //如果ret==""。说明当前buffer_stream不足以是一个完成的报文
                                break; //退出这个循环，回到上面read，直到将完成的报文拿到

                            // 写回
                            int ret_wrt = write(sockfd, ret.c_str(), ret.size());
                            if (ret_wrt < 0)
                            {
                                lg(Warning, "serve write fail...");
                                close(sockfd);
                                exit(1);
                            }
                        }
                    }
                    else if (ret_rd == 0)
                        break;
                    else
                        break;
                }
                lg(Info, "Client quit...ip:%s, port:%d", clientip.c_str(), clientport);
                close(sockfd);
                exit(0);
            }

            close(sockfd); // 父进程直接关闭fd
        }
    }

private:
    TcpSocket _listensock; // 接口使用
    uint16_t _port;
    func_t _callback; // 回调函数 调用Calculate函数
};